﻿#ifdef WIN32

#include "Platform/Window/WindowsWindow.h"
#include "WindowsThread.h"
#include "Platform/Windows/WindowsDropTarget.h"
#include "Platform/TextInput/WindowsTextInputManager.h"

#include <windowsx.h>

static CWindowsOSThread* WindowsOSThread = nullptr;


EKey ToEngineKey(WPARAM InKey,LPARAM lParam)
{
    switch(InKey)
    {
        //list of virtual keyborad key code in order of the value
        case VK_BACK : return EKey::Backspace;
        case VK_TAB : return EKey::Tab;
        case VK_RETURN : return EKey::Enter;
        case VK_SHIFT : 
        {
            if(HIWORD(lParam) & KF_EXTENDED)
            {
                return EKey::RShift;
            }
            else
            {
                return EKey::LShift;
            }
        }
        case VK_CONTROL : 
        {
            if(HIWORD(lParam) & KF_EXTENDED)
            {
                return EKey::RControl;
            }
            else
            {
                return EKey::LControl;
            }
        }
        case VK_MENU : 
        {
            if(HIWORD(lParam) & KF_EXTENDED)
            {
                return EKey::RAlt;
            }
            else
            {
                return EKey::LAlt;
            }
        }
        case VK_PAUSE : return EKey::Pause;
        case VK_CAPITAL : return EKey::CapsLock;
        case VK_ESCAPE : return EKey::Escape;
        case VK_SPACE : return EKey::Space;
        case VK_PRIOR : return EKey::PageUp;
        case VK_NEXT : return EKey::PageDown;
        case VK_END : return EKey::End;
        case VK_HOME : return EKey::Home;
        case VK_LEFT : return EKey::Left;
        case VK_UP : return EKey::Up;
        case VK_RIGHT : return EKey::Right;
        case VK_DOWN : return EKey::Down;
        case VK_SELECT : return EKey::UnSupportedKey; //my keyboard does not have this key, so I do not know what it is
        case VK_PRINT : return EKey::UnSupportedKey;
        case VK_EXECUTE : return EKey::UnSupportedKey;
        case VK_SNAPSHOT : return EKey::PrintScreen;
        case VK_INSERT : return EKey::Insert;
        case VK_DELETE : return EKey::Delete;
        case VK_HELP : return EKey::UnSupportedKey;
        case 0x30 : return EKey::Key0;
        case 0x31 : return EKey::Key1;
        case 0x32 : return EKey::Key2;
        case 0x33 : return EKey::Key3;
        case 0x34 : return EKey::Key4;
        case 0x35 : return EKey::Key5;
        case 0x36 : return EKey::Key6;
        case 0x37 : return EKey::Key7;
        case 0x38 : return EKey::Key8;
        case 0x39 : return EKey::Key9;
        case 0x41 : return EKey::A;
        case 0x42 : return EKey::B;
        case 0x43 : return EKey::C;
        case 0x44 : return EKey::D;
        case 0x45 : return EKey::E;
        case 0x46 : return EKey::F;
        case 0x47 : return EKey::G;
        case 0x48 : return EKey::H;
        case 0x49 : return EKey::I;
        case 0x4A : return EKey::J;
        case 0x4B : return EKey::K;
        case 0x4C : return EKey::L;
        case 0x4D : return EKey::M;
        case 0x4E : return EKey::N;
        case 0x4F : return EKey::O;
        case 0x50 : return EKey::P;
        case 0x51 : return EKey::Q;
        case 0x52 : return EKey::R;
        case 0x53 : return EKey::S;
        case 0x54 : return EKey::T;
        case 0x55 : return EKey::U;
        case 0x56 : return EKey::V;
        case 0x57 : return EKey::W;
        case 0x58 : return EKey::X;
        case 0x59 : return EKey::Y;
        case 0x5A : return EKey::Z;
        case VK_LWIN : return EKey::LSystem;
        case VK_RWIN : return EKey::RSystem;
        case VK_APPS : return EKey::Menu;
        case VK_SLEEP : return EKey::UnSupportedKey; 
        case VK_NUMPAD0 : return EKey::NumPad0;
        case VK_NUMPAD1 : return EKey::NumPad1;
        case VK_NUMPAD2 : return EKey::NumPad2;
        case VK_NUMPAD3 : return EKey::NumPad3;
        case VK_NUMPAD4 : return EKey::NumPad4;
        case VK_NUMPAD5 : return EKey::NumPad5;
        case VK_NUMPAD6 : return EKey::NumPad6;
        case VK_NUMPAD7 : return EKey::NumPad7;
        case VK_NUMPAD8 : return EKey::NumPad8;
        case VK_NUMPAD9 : return EKey::NumPad9;
        case VK_MULTIPLY : return EKey::NumPadMultiply;
        case VK_ADD : return EKey::NumPadAdd;
        case VK_SEPARATOR : return EKey::UnSupportedKey;
        case VK_SUBTRACT : return EKey::NumPadSubtract;
        case VK_DECIMAL : return EKey::NumPadDecimal;
        case VK_DIVIDE : return EKey::NumPadDivide;
        case VK_F1 : return EKey::F1;
        case VK_F2 : return EKey::F2;
        case VK_F3 : return EKey::F3;
        case VK_F4 : return EKey::F4;
        case VK_F5 : return EKey::F5;
        case VK_F6 : return EKey::F6;
        case VK_F7 : return EKey::F7;
        case VK_F8 : return EKey::F8;
        case VK_F9 : return EKey::F9;
        case VK_F10 : return EKey::F10;
        case VK_F11 : return EKey::F11;
        case VK_F12 : return EKey::F12;
        case VK_F13 : return EKey::UnSupportedKey;
        case VK_F14 : return EKey::UnSupportedKey;
        case VK_F15 : return EKey::UnSupportedKey;
        case VK_F16 : return EKey::UnSupportedKey;
        case VK_F17 : return EKey::UnSupportedKey;
        case VK_F18 : return EKey::UnSupportedKey;
        case VK_F19 : return EKey::UnSupportedKey;
        case VK_F20 : return EKey::UnSupportedKey;
        case VK_F21 : return EKey::UnSupportedKey;
        case VK_F22 : return EKey::UnSupportedKey;
        case VK_F23 : return EKey::UnSupportedKey;
        case VK_F24 : return EKey::UnSupportedKey;
        case VK_NUMLOCK : return EKey::NumLock;
        case VK_SCROLL : return EKey::ScrollLock;
        case VK_OEM_1 : return EKey::Semicolon;
        case VK_OEM_PLUS : return EKey::Equal;
        case VK_OEM_COMMA : return EKey::Comma;
        case VK_OEM_MINUS : return EKey::Minus;
        case VK_OEM_PERIOD : return EKey::Period;
        case VK_OEM_2 : return EKey::Slash;
        case VK_OEM_3 : return EKey::Tilde;
        case VK_OEM_4 : return EKey::LBracket;
        case VK_OEM_5 : return EKey::BackSlash;
        case VK_OEM_6 : return EKey::RBracket;
        case VK_OEM_7 : return EKey::Apostrophe;
        
        default: return EKey::UnSupportedKey;

    }
}

WPARAM CWindowsOSThread::ToWindowsKey(EKey InKey)
{
    switch(InKey)
    {
        case EKey::Escape: return VK_ESCAPE;
        case EKey::F1: return VK_F1;
        case EKey::F2: return VK_F2;
        case EKey::F3: return VK_F3;
        case EKey::F4: return VK_F4;
        case EKey::F5: return VK_F5;
        case EKey::F6: return VK_F6;
        case EKey::F7: return VK_F7;
        case EKey::F8: return VK_F8;
        case EKey::F9: return VK_F9;
        case EKey::F10: return VK_F10;
        case EKey::F11: return VK_F11;
        case EKey::F12: return VK_F12;
        case EKey::PrintScreen: return VK_SNAPSHOT;
        case EKey::ScrollLock: return VK_SCROLL;
        case EKey::Pause: return VK_PAUSE;
        case EKey::Tilde: return VK_OEM_3;
        case EKey::NumPad0: return VK_NUMPAD0;
        case EKey::NumPad1: return VK_NUMPAD1;
        case EKey::NumPad2: return VK_NUMPAD2;
        case EKey::NumPad3: return VK_NUMPAD3;
        case EKey::NumPad4: return VK_NUMPAD4;
        case EKey::NumPad5: return VK_NUMPAD5;
        case EKey::NumPad6: return VK_NUMPAD6;
        case EKey::NumPad7: return VK_NUMPAD7;
        case EKey::NumPad8: return VK_NUMPAD8;
        case EKey::NumPad9: return VK_NUMPAD9;
        case EKey::NumPadMultiply: return VK_MULTIPLY;
        case EKey::NumPadDivide: return VK_DIVIDE;
        case EKey::NumPadAdd: return VK_ADD;
        case EKey::NumPadSubtract: return VK_SUBTRACT;
        case EKey::NumPadDecimal: return VK_DECIMAL;
        case EKey::NumLock: return VK_NUMLOCK;
        case EKey::Semicolon: return VK_OEM_1;
        case EKey::Equal: return VK_OEM_PLUS;
        case EKey::Comma: return VK_OEM_COMMA;
        case EKey::Minus: return VK_OEM_MINUS;
        case EKey::Period: return VK_OEM_PERIOD;
        case EKey::Slash: return VK_OEM_2;
        case EKey::LBracket: return VK_OEM_4;
        case EKey::BackSlash: return VK_OEM_5;
        case EKey::RBracket: return VK_OEM_6;
        case EKey::Apostrophe: return VK_OEM_7;
        case EKey::Key0: return 0x30;
        case EKey::Key1: return 0x31;
        case EKey::Key2: return 0x32;
        case EKey::Key3: return 0x33;
        case EKey::Key4: return 0x34;
        case EKey::Key5: return 0x35;
        case EKey::Key6: return 0x36;
        case EKey::Key7: return 0x37;
        case EKey::Key8: return 0x38;
        case EKey::Key9: return 0x39;
        case EKey::A: return 0x41;
        case EKey::B: return 0x42;
        case EKey::C: return 0x43;
        case EKey::D: return 0x44;
        case EKey::E: return 0x45;
        case EKey::F: return 0x46;
        case EKey::G: return 0x47;
        case EKey::H: return 0x48;
        case EKey::I: return 0x49;
        case EKey::J: return 0x4A;
        case EKey::K: return 0x4B;
        case EKey::L: return 0x4C;
        case EKey::M: return 0x4D;
        case EKey::N: return 0x4E;
        case EKey::O: return 0x4F;
        case EKey::P: return 0x50;
        case EKey::Q: return 0x51;
        case EKey::R: return 0x52;
        case EKey::S: return 0x53;
        case EKey::T: return 0x54;
        case EKey::U: return 0x55;
        case EKey::V: return 0x56;
        case EKey::W: return 0x57;
        case EKey::X: return 0x58;
        case EKey::Y: return 0x59;
        case EKey::Z: return 0x5A;
        case EKey::Backspace: return VK_BACK;
        case EKey::Tab: return VK_TAB;
        case EKey::Enter: return VK_RETURN;
        case EKey::CapsLock: return VK_CAPITAL;
        case EKey::Space: return VK_SPACE;
        case EKey::PageUp: return VK_PRIOR;
        case EKey::PageDown: return VK_NEXT;
        case EKey::End: return VK_END;
        case EKey::Home: return VK_HOME;
        case EKey::Left: return VK_LEFT;
        case EKey::Up: return VK_UP;
        case EKey::Right: return VK_RIGHT;
        case EKey::Down: return VK_DOWN;
        case EKey::Insert: return VK_INSERT;
        case EKey::Delete: return VK_DELETE;
        case EKey::LSystem: return VK_LWIN;
        case EKey::RSystem: return VK_RWIN;
        case EKey::Menu: return VK_APPS;
        case EKey::LShift: return VK_LSHIFT;
        case EKey::RShift: return VK_RSHIFT;
        case EKey::LControl: return VK_LCONTROL;
        case EKey::RControl: return VK_RCONTROL;
        case EKey::LAlt: return VK_LMENU;
        case EKey::RAlt: return VK_RMENU;
        default: 
        {
            assert(false&& "UnSupportedKey");
            return 0;
        }

    }
}

void CWindowsOSThread::StartTextInput(uint64_t WindowID, SIntPoint IMEWidgetPosition)
{
    TextInputStartData = {WindowID,IMEWidgetPosition};

    //等待输入法开始
    while(TextInputStartData.load().WindowID)
    {
        std::this_thread::yield();
    }
}

void CWindowsOSThread::StopTextInput()
{
    bWaitingStopTextInput = true;

    //等待输入法停止
    while(bWaitingStopTextInput)
    {
        std::this_thread::yield();
    }
   
}

bool CWindowsOSThread::IsTextInputStarted() const
{
    return TextInputInterface->IsTextInputStarted();
}

void CWindowsOSThread::UseSystemCursor(EMouseCursorType CursorType)
{
    DesiredCursorType=CursorType;
}

SIntPoint CWindowsOSThread::LastScreenMousePosition={0,0};

bool CWindowsOSThread::bWaitingNextChar = false;
//windows message process function
LRESULT CALLBACK CWindowsOSThread::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_GETMINMAXINFO:
    {
        //Limit maximum window size
        //when maximize the borderless window, window will cover the whole screen(include taskbar) 
        //so have to limit the maximum size of the window
        
        auto Window=CWindowsOSThread::GetWindowFromID((uint64_t)hwnd);
        assert(Window);

        //将窗口限制在工作区域内
        auto MaxWorkArea= Window->GetScreenPlacableArea();
        //set the max size  of the window
        MINMAXINFO* pInfo = (MINMAXINFO*)lParam;
        pInfo->ptMaxPosition.x = MaxWorkArea.Min.X;
        pInfo->ptMaxPosition.y = MaxWorkArea.Min.Y;
        pInfo->ptMaxSize.x = MaxWorkArea.Extent.X;
        pInfo->ptMaxSize.y = MaxWorkArea.Extent.Y;
        break;
    }

    case WM_SETCURSOR:
    {

        auto Low=LOWORD(lParam);
        auto High=HIWORD(lParam);
        auto Error=uint16_t(HTERROR);

        if (Low == Error 
            && 
            (High==WM_LBUTTONDOWN
            || High==WM_RBUTTONDOWN
            || High==WM_MBUTTONDOWN
            ))
        { 
            //when user click the disabled window
            //will receive a WM_SETCURSOR message with HTERROR
            //https://learn.microsoft.com/zh-cn/windows/win32/menurc/wm-setcursor
            
            LRESULT lrst= DefWindowProcW(hwnd, uMsg, wParam, lParam);
            
            SSystemClickDisabledWindow Event;
            Event.WindowID = (uint64_t)hwnd;

            std::lock_guard lock(WindowsOSThread->EventQueueMutex);
            WindowsOSThread->EventQueue.push(Event);
            return lrst;
        } 
    }
    break;


    //listen the window close message
    case WM_CLOSE:
    {
        SSystemWindowClose Event;
        Event.WindowID = (uint64_t)hwnd;

        std::lock_guard lock(WindowsOSThread->EventQueueMutex);
        WindowsOSThread->EventQueue.push(Event);
        
        //对于窗口关闭消息，返回0表示不关闭窗口
        return 0;
    }


    case WM_DESTROY:
        //PostQuitMessage(0);
        return 0;

    case WM_LBUTTONDOWN:
    {

        SSystemMouseButtonDown Event;
        Event.WindowID = (uint64_t)hwnd;
        Event.Button = EMouseButton::Left;

        std::lock_guard lock(WindowsOSThread->EventQueueMutex);
        WindowsOSThread->EventQueue.push(Event);


        return 0;
    }

    case WM_LBUTTONDBLCLK:
    {

        SSystemMouseButtonDown Event;
        Event.WindowID = (uint64_t)hwnd;
        Event.Button = EMouseButton::Left;
        Event.DoubleClick = true;

        std::lock_guard lock(WindowsOSThread->EventQueueMutex);
        WindowsOSThread->EventQueue.push(Event);

        return 0;
    }

    case WM_LBUTTONUP:
    {

        SSystemMouseButtonUp Event;
        Event.WindowID = (uint64_t)hwnd;
        Event.Button = EMouseButton::Left;

        std::lock_guard lock(WindowsOSThread->EventQueueMutex);
        WindowsOSThread->EventQueue.push(Event);

        return 0;
    }

    case WM_RBUTTONDOWN:
    {
        SSystemMouseButtonDown Event;
        Event.WindowID = (uint64_t)hwnd;
        Event.Button = EMouseButton::Right;

        std::lock_guard lock(WindowsOSThread->EventQueueMutex);
        WindowsOSThread->EventQueue.push(Event);


        return 0;

    }

    case WM_RBUTTONDBLCLK:
    {

        SSystemMouseButtonDown Event;
        Event.WindowID = (uint64_t)hwnd;
        Event.Button = EMouseButton::Right;
        Event.DoubleClick = true;

        std::lock_guard lock(WindowsOSThread->EventQueueMutex);
        WindowsOSThread->EventQueue.push(Event);


        return 0;
    }

    case WM_RBUTTONUP:
    {
        SSystemMouseButtonUp Event;
        Event.WindowID = (uint64_t)hwnd;
        Event.Button = EMouseButton::Right;

        std::lock_guard lock(WindowsOSThread->EventQueueMutex);
        WindowsOSThread->EventQueue.push(Event);


        return 0;
    }

    case WM_MBUTTONDOWN:
    {

        SSystemMouseButtonDown Event;
        Event.WindowID = (uint64_t)hwnd;
        Event.Button = EMouseButton::Middle;

        std::lock_guard lock(WindowsOSThread->EventQueueMutex);
        WindowsOSThread->EventQueue.push(Event);
        return 0;
    }

    case WM_MBUTTONDBLCLK:
    {
        SSystemMouseButtonDown Event;
        Event.WindowID = (uint64_t)hwnd;
        Event.Button = EMouseButton::Middle;
        Event.DoubleClick = true;

        std::lock_guard lock(WindowsOSThread->EventQueueMutex);
        WindowsOSThread->EventQueue.push(Event);

        return 0;
    }

    case WM_MBUTTONUP:
    {
        SSystemMouseButtonUp Event;
        Event.WindowID = (uint64_t)hwnd;
        Event.Button = EMouseButton::Middle;

        std::lock_guard lock(WindowsOSThread->EventQueueMutex);
        WindowsOSThread->EventQueue.push(Event);

        return 0;
    }

    case WM_MOUSEMOVE:
    case WM_NCMOUSEMOVE: //当鼠标在窗口外且按下鼠标按键时的移动消息
    {

        SSystemMouseMove Event;
        Event.WindowID = (uint64_t)hwnd;
        Event.MousePosition.X=GET_X_LPARAM(lParam);
        Event.MousePosition.Y=GET_Y_LPARAM(lParam);

        POINT ScreenMousePosition;
        GetCursorPos(&ScreenMousePosition);
        Event.ScreenMousePosition={ScreenMousePosition.x,ScreenMousePosition.y};

        Event.Delta.X=Event.MousePosition.X-LastScreenMousePosition.X;
        Event.Delta.Y=Event.MousePosition.Y-LastScreenMousePosition.Y;

        std::lock_guard lock(WindowsOSThread->EventQueueMutex);
        WindowsOSThread->EventQueue.push(Event);
        return 0;
    }

    case WM_MOUSEWHEEL:
    {
        SSystemMouseWheelRoll Event;
        Event.WindowID = (uint64_t)hwnd;
        Event.WheelDistance = GET_WHEEL_DELTA_WPARAM(wParam)/WHEEL_DELTA;

        std::lock_guard lock(WindowsOSThread->EventQueueMutex);
        WindowsOSThread->EventQueue.push(Event);
        return 0;
    }

    case WM_SYSKEYDOWN:
    {
        SSystemKeyboardKeyDown Event;
        Event.WindowID = (uint64_t)hwnd;
        Event.Key = ToEngineKey(wParam, lParam);

        std::lock_guard lock(WindowsOSThread->EventQueueMutex);
        WindowsOSThread->EventQueue.push(Event);

        return 0;
    }

    case WM_SYSKEYUP:
    {
        SSystemKeyboardKeyUp Event;
        Event.WindowID = (uint64_t)hwnd;
        Event.Key = ToEngineKey(wParam, lParam);
      
        std::lock_guard lock(WindowsOSThread->EventQueueMutex);
        WindowsOSThread->EventQueue.push(Event);

        return 0;
    }

    case WM_KEYDOWN:
    {
        auto Key = ToEngineKey(wParam, lParam);
        if(Key==EKey::UnSupportedKey)
        {
            return 0;
        }

        SSystemKeyboardKeyDown Event;
        Event.WindowID = (uint64_t)hwnd;
        Event.Key = Key;

        std::lock_guard lock(WindowsOSThread->EventQueueMutex);
        WindowsOSThread->EventQueue.push(Event);

        return 0;    
    }

    case WM_KEYUP:
    {
        SSystemKeyboardKeyUp Event;
        Event.WindowID = (uint64_t)hwnd;
        Event.Key = ToEngineKey(wParam, lParam);

        std::lock_guard lock(WindowsOSThread->EventQueueMutex);
        WindowsOSThread->EventQueue.push(Event);
        return 0;
    }

    case WM_CHAR:
    {
        //when wParam<31 ,it is might be a control key, such as ctrl+s will send a WM_CHAR message with wParam=19
        //those control key can't trait as text input
        //https://www.physics.udel.edu/~watson/scen103/ascii.html
        if(wParam<31)
        {
            return 0;
        }

        static char16_t InputChar[3]={0,0,u'\0'};
        if(bWaitingNextChar)
        {
            InputChar[1] = (char16_t)wParam;
            bWaitingNextChar = false;

            SSystemTextInput Event;
            Event.WindowID = (uint64_t)hwnd;
            Event.Text = CString(InputChar);

            std::lock_guard lock(WindowsOSThread->EventQueueMutex);
            WindowsOSThread->EventQueue.push(Event);
            return 0;
        }

        //a utf16 character's first byte is 0xD8
        if((wParam & 0xFF00) == 0xD800)
        {
            //this is a utf16 character's first byte
            //store it and wait for the second byte
            InputChar[0] = (char16_t)wParam;
            bWaitingNextChar = true;
            return 0;
        }

        //只需要一个16位的字符
        SSystemTextInput Event;
        Event.WindowID = (uint64_t)hwnd;
        InputChar[0] = (char16_t)wParam;
        InputChar[1] = u'\0';
        Event.Text = CString(InputChar);

        std::lock_guard lock(WindowsOSThread->EventQueueMutex);
        WindowsOSThread->EventQueue.push(Event);
        return 0;

    }

    case WM_SIZE:
    {
        SSystemWindowResize Event;
        Event.WindowID = (uint64_t)hwnd;
        Event.NewSize.X = LOWORD(lParam);
        Event.NewSize.Y = HIWORD(lParam);

        std::lock_guard lock(WindowsOSThread->EventQueueMutex);
        WindowsOSThread->EventQueue.push(Event);

        return 0;
    }

    case WM_KILLFOCUS:
    {
        //窗口失去焦点，用户切换到其他窗口
        SSystemWindowLostFocus Event;
        Event.WindowID = (uint64_t)hwnd;
        Event.FocusedWindowID= (uint64_t)wParam;

        std::lock_guard lock(WindowsOSThread->EventQueueMutex);
        WindowsOSThread->EventQueue.push(Event);

        return 0;
    }

    case WM_SETFOCUS:
    {
        //窗口获得焦点，用户切换到这个窗口
        SSystemWindowGotFocus Event;
        Event.WindowID = (uint64_t)hwnd;

        std::lock_guard lock(WindowsOSThread->EventQueueMutex);
        WindowsOSThread->EventQueue.push(Event);

        return 0;
    }

    default :
        break;
    }

    LRESULT lrst= DefWindowProcW(hwnd, uMsg, wParam, lParam);
    return lrst;

}



CWindowsOSThread::CWindowsOSThread()
{

    WindowsOSThread=this;

    bIsRunning=true;
    Thread=new std::thread([this] {

        TextInputInterface= new CWindowsInputMethodEditor();

        CreateAndRegisterWindowClass();

        //initialize COM, so that can use COM interface
        //such as DropTarget
        ::OleInitialize(NULL);

        //获取当前鼠标位置
        {
            POINT MousePosition;
            GetCursorPos(&MousePosition);
            LastScreenMousePosition={MousePosition.x,MousePosition.y};
        }

        while(true)
        {
            //创建窗口
            if(bIsWaitingCreateWindow)
            {
                CreatedWindow = InnerCreateWindow();
                bIsWaitingCreateWindow = false;
            }

            //销毁窗口
            if(WaitingDestroyWindow)
            {
                InnerDestroyWindow(WaitingDestroyWindow);
                WaitingDestroyWindow = nullptr;
            }

            //设置窗口长整数
            if(bIsWaitingSetWindowLong)
            {
                SetWindowLongW((HWND)SetWindowLongWindowID, SetWindowLongIndex, SetWindowLongNewLong);
                bIsWaitingSetWindowLong = false;
            }

            //开始输入法
            auto TempTextInputStartData = TextInputStartData.load();
            if(TempTextInputStartData.WindowID)
            {
                InnerStartTextInput(TempTextInputStartData.WindowID, TempTextInputStartData.IMEWidgetPosition);
                TextInputStartData={0,{0,0}};
            }

            //停止输入法
            auto _bWaitingStopTextInput=bWaitingStopTextInput.load();
            if(_bWaitingStopTextInput)
            {
                TextInputInterface->StopTextInput();
                bWaitingStopTextInput = false;
            } 

            //修改鼠标指针
            auto _DesiredCursorType=DesiredCursorType.load();
            if(_DesiredCursorType!=CurrentCursorType)
            {
                InnerUseSystemCursor(_DesiredCursorType);
                CurrentCursorType=_DesiredCursorType;
            }

            //消息循环
            MessageLoop();

            //捕获鼠标
            {
                uint64_t TempWantedWindowID = WantedMouseCaptureWindowID.load();
                if(TempWantedWindowID!=MouseCapturedWindowID)
                {
                    if(TempWantedWindowID!=0)
                    {
                        HWND CapturedWindow=SetCapture((HWND)TempWantedWindowID);
                        MouseCapturedWindowID=TempWantedWindowID;
                    }
                    else
                    {
                        ReleaseCapture();
                        MouseCapturedWindowID=0;
                    }
                    
                }
            }
          
        
            //防止CPU时间占用过高导致其他线程无法抢到CPU时间片
            std::this_thread::yield();
        }
    });





}

CWindowsOSThread::~CWindowsOSThread()
{
    bIsRunning=false;
    Thread->join();
    delete Thread;
    Thread=nullptr;
    ::OleUninitialize();

    WindowsOSThread=nullptr;
}

CWindowsOSThread *CWindowsOSThread::Get()
{
    return WindowsOSThread;
}

CWindowsWindow *CWindowsOSThread::CreateWindowWithBlock()
{
    bIsWaitingCreateWindow = true;

    //等待窗口创建完成
    while (bIsWaitingCreateWindow)
    {
        std::this_thread::yield();
    }

    auto NewWindow=CreatedWindow;
    CreatedWindow= nullptr;

    return NewWindow;
}

void CWindowsOSThread::SetWindowLongWithBlock(uint64_t WindowID, int Index, LONG NewLong)
{
    SetWindowLongWindowID=WindowID;
    SetWindowLongIndex=Index;
    SetWindowLongNewLong=NewLong;
    bIsWaitingSetWindowLong=true;

    //等待设置完成
    while(bIsWaitingSetWindowLong)
    {
        std::this_thread::yield();
    }
}

void CWindowsOSThread::DestroyWindowWithBlock(CWindowsWindow *InWindowToDestroy)
{
    WaitingDestroyWindow=InWindowToDestroy;

    //等待窗口销毁
    while(WaitingDestroyWindow)
    {
        std::this_thread::yield();
    }
}

TOptional<SystemEvent> CWindowsOSThread::PopEvent()
{
    std::lock_guard lock(EventQueueMutex);
    if(EventQueue.empty())
    {
        return TOptional<SystemEvent>();
    }

    auto Event=EventQueue.front();
    EventQueue.pop();
    return Event;
}

CWindowsWindow *CWindowsOSThread::GetWindowFromID(uint64_t WindowID)
{
    return (CWindowsWindow*)GetWindowLongPtr((HWND)WindowID, GWLP_USERDATA);
}

void CWindowsOSThread::CreateAndRegisterWindowClass()
{
    //创建窗口类
    WNDCLASSW wc = { 0 };
    wc.lpfnWndProc = CWindowsOSThread::WindowProc;
    wc.hInstance = GetModuleHandle(NULL);
    wc.lpszClassName = L"WuhuaEngineWindowClass";
    wc.style = CS_HREDRAW | CS_VREDRAW |   CS_DBLCLKS ;

    //注册窗口类
    RegisterClassW(&wc);
}

void CWindowsOSThread::MessageLoop()
{
    MSG msg = { 0 };
    if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
    {
        //translate the message and dispatch it to the window procedure
        TranslateMessage(&msg);
        DispatchMessage(&msg);

        if(bWaitingNextChar)
        {
            //dispatch the next char message
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

}

CWindowsWindow* CWindowsOSThread::InnerCreateWindow()
{
    CWindowsWindow* Window=new CWindowsWindow();

    Window->HInstance= GetModuleHandle(NULL);

    Window->Hwnd =(uint64_t)CreateWindowW(L"WuhuaEngineWindowClass"
        , L"NoNameWindow"
        , // WS_VISIBLE|
        WS_POPUP 
        //WS_POPUP    //borderless, if donot paint anything, it will be fully transparent
        , 0, 0, 800, 600
        , nullptr, nullptr, Window->HInstance, nullptr);

    assert(Window-> Hwnd && "create window failed");

    //enable drag and drop
    //DragAcceptFiles((HWND)Hwnd, true);

    //disable ime, user might using Editing text on other window/application
    //when create this window, we should disable ime until user edit text on this window 
    ImmAssociateContext((HWND)Window-> Hwnd, NULL);

    //绑定窗口指针
    SetWindowLongPtrW((HWND)Window-> Hwnd, GWLP_USERDATA, (LONG_PTR)Window);

    //设置口边框，只能在绑定窗口指针后，否则会触发WM_GETMINMAXINFO消息
    //而在WM_GETMINMAXINFO消息中设置窗口最大值需要绑定窗口指针
    SetWindowLongW((HWND)Window-> Hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
    //让WS_OVERLAPPEDWINDOW 生效
    SetWindowPos((HWND)Window-> Hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);

    //register drop target
    {
        Window->DropTarget= new SWindowsDropTarget(Window-> Hwnd);
        HRESULT Result=::RegisterDragDrop((HWND)Window-> Hwnd, (IDropTarget*)Window->DropTarget);
        if(Result!=S_OK)
        {
            //failed to register drop target
            //maybe forget to call OleInitialize(NULL)

            delete (SWindowsDropTarget*)Window->DropTarget;
            Window->DropTarget=nullptr;
        }
    }

    return Window;
}

void CWindowsOSThread::InnerDestroyWindow(CWindowsWindow* InWindow)
{
    //unregister drop target
    if(InWindow->DropTarget)
    {
        ::RevokeDragDrop((HWND)InWindow->Hwnd);
        delete (SWindowsDropTarget*)InWindow->DropTarget;
    }

    //销毁窗口
    DestroyWindow((HWND)InWindow->Hwnd);

    delete InWindow;
}

void CWindowsOSThread::InnerStartTextInput(uint64_t WindowID, SIntPoint IMEWidgetPosition)
{
    //make sure the window is focused
    auto FocusedWindow = (uint64_t)SetFocus((HWND)WindowID);
    TextInputInterface->StartTextInput(WindowID, IMEWidgetPosition.X, IMEWidgetPosition.Y);
}

void CWindowsOSThread::InnerStopTextInput()
{
    TextInputInterface->StopTextInput();
}

void CWindowsOSThread::InnerUseSystemCursor(EMouseCursorType CursorType)
{
    //change the cursor shape
    HCURSOR hCursor = LoadCursor(NULL, IDC_ARROW);
    switch (CursorType)
    {
    case EMouseCursorType::Arrow:
        hCursor = LoadCursor(NULL, IDC_ARROW);
        break;
    case EMouseCursorType::IBeam:
        hCursor = LoadCursor(NULL, IDC_IBEAM);
        break;
    case EMouseCursorType::ResizeHorizontal:
        hCursor = LoadCursor(NULL, IDC_SIZEWE);
        break;
    case EMouseCursorType::ResizeVertical:
        hCursor = LoadCursor(NULL, IDC_SIZENS);
        break;
    case EMouseCursorType::ResizeLeftTopTORightBottom:
        hCursor = LoadCursor(NULL, IDC_SIZENWSE);
        break;
    case EMouseCursorType::ResizeRightTopTOLeftBottom:
        hCursor = LoadCursor(NULL, IDC_SIZENESW);
        break;
    case EMouseCursorType::Hand:
        hCursor = LoadCursor(NULL, IDC_HAND);
        break;
    case EMouseCursorType::No:
        hCursor = LoadCursor(NULL, IDC_NO);
        break;
    case EMouseCursorType::Wait:
        hCursor = LoadCursor(NULL, IDC_WAIT);
        break;
    case EMouseCursorType::ResizeAll:
        hCursor = LoadCursor(NULL, IDC_SIZEALL);
        break;
    case EMouseCursorType::Crosshair:
        hCursor = LoadCursor(NULL, IDC_CROSS);
        break;
    case EMouseCursorType::WaitAndArrow:
        hCursor = LoadCursor(NULL, IDC_APPSTARTING);
        break;

    default:
        assert(false);
        break;
    }

    SetCursor(hCursor);
}

void CWindowsOSThread::OnDragFileEnter(uint64_t Window, const TVector<SPath> &InFiles)
{
    DragFileOverWindow=Window;
    DragingFiles=InFiles;
}

void CWindowsOSThread::OnDragFileLeave()
{
    //clear the file path
    DragingFiles.Clear();
    DragFileOverWindow=0;
}

void CWindowsOSThread::OnDragFileOver()
{
    //create mouse move event with file path
    SSystemDragFileOver Event;
    Event.WindowID=DragFileOverWindow;
    Event.FilePaths = DragingFiles;

    std::lock_guard lock(EventQueueMutex);
    EventQueue.push(Event);
}

void CWindowsOSThread::OnFiledDroped()
{
    SSystemDropFiles Event;
    Event.WindowID=DragFileOverWindow;
    Event.FilePaths = DragingFiles;

    //clear the file path
    DragingFiles.Clear();
    DragFileOverWindow=0;

    std::lock_guard lock(WindowsOSThread->EventQueueMutex);
    EventQueue.push(Event);
}

void CWindowsOSThread::CaptureMouse(uint64_t WindowID)
{
    WantedMouseCaptureWindowID=WindowID;
}

void CWindowsOSThread::ReleaseMouseCapture()
{
    WantedMouseCaptureWindowID=0;
}

#endif